inline
opt_feat::opt_feat(const std::string in_path,
		   const std::string in_actionNames,  
		   const uword in_col, 
		   const uword in_row
)
:path(in_path), actionNames(in_actionNames), col(in_col), row(in_row)
{
  actions.load( actionNames );  //actions.print("All actions");
  dim = 416; //dense trayectories
}



inline
void
opt_feat::features_per_action_training( field<string>peo_train ) 
{
  std::vector < vec > feat_all_videos_action_i;
  int n_actions = actions.n_rows;
  all_actions_matrix.resize(n_actions);
  //cout << "size " << all_actions_matrix.size() << endl;
  
  /*for (uword b=0;  b< all_actions_matrix.size(); ++b)
   *    {
   *      cout << all_actions_matrix.at(b).size() << " ";
   }
   */cout << endl;
   
   
   int n_peo_tr =  peo_train.n_rows;
   
   for (int pe = 0; pe< n_peo_tr; ++pe)
   {
     
     all_actions_matrix.clear();
     all_actions_matrix.resize(n_actions);
     
     std::stringstream ss_features;
     ss_features << "./features/dense/" << peo_train(pe) ;
     
     mat dense_features;
     dense_features.load( ss_features.str() );
     
     cout << "r&c: " << dense_features.n_rows << " & " << dense_features.n_cols << endl;
     int num_feat_vect = dense_features.n_rows;
     //getchar();
     
     //load labels and range
     std::stringstream ss_label_name;
     ss_label_name << path <<  peo_train (pe) << "_unique_verbs_labels.dat";
     std::string sLabel = ss_label_name.str();
     vec labels; 
     labels.load( sLabel );
     int nLabels =  labels.n_elem;
     cout << "# labels " << nLabels << endl;
     std::stringstream ss_range_frames;
     ss_range_frames << path <<  peo_train (pe) << "_start_end.dat";
     std::string sRange_frames = ss_range_frames.str();
     rowvec range_frame;
     range_frame.load( sRange_frames );
     range_frame.print("ini end");
     int ini_frame = range_frame(0);
     int end_frame = range_frame(1);
     
     
     for (int fv=0; fv<num_feat_vect; ++fv )
     {
       
       vec one_vector= dense_features.row(fv).t();
       uword fr_ind =  one_vector(0); // the first feature is the frame number
       int lab_ind = fr_ind - ini_frame;
       
       if (fr_ind > ini_frame &&  fr_ind <  nLabels )
       {
	
	//cout << "fv: "<< fv << ". fr_ind "<< fr_ind;
	uword pos = labels(lab_ind - 1) - 1;
	//cout << ". lab: "<< pos << endl;
	
	double is_zero = accu( abs( one_vector ) );
	
	 if (is_finite( one_vector ) && is_zero!=0 )
	 {
	   all_actions_matrix.at(pos).push_back(one_vector);
	 }
	 //getchar();
       }
       
     }
     
     dense_features.reset();
     
     //cout << fr_ind << endl;
     //getchar();
   
       
       for (int act=0; act<n_actions; ++act)
       {
	 feat_all_videos_action_i = all_actions_matrix.at(act);
	 //cout << feat_all_videos_action_i.size() << endl;
	 //cout << feat_all_videos_action_i.at(0).size() << endl;
	 
	 
	 mat mat_features;
	 if (feat_all_videos_action_i.size()>0)
	 {
	   mat_features.zeros(dim,feat_all_videos_action_i.size());
	   
	   
	   for (uword i = 0; i < feat_all_videos_action_i.size(); ++i)
	   {
	     
	     mat_features.col(i) = feat_all_videos_action_i.at(i);
	     //cout << i << " " ;
	     
	   }
	 }
	 else
	 {
	   mat_features.zeros(dim,0);
	 }
	 
	 
	 std::stringstream tmp_ss4;
	 tmp_ss4 << "./features/train/feature_vectors_dim" << dim << "_" << peo_train (pe) << "_" << actions(act);
	 cout << "Saving at " << tmp_ss4.str() << endl;
	 cout << mat_features.n_rows << " " << mat_features.n_cols << endl;
	 mat_features.save( tmp_ss4.str() );
	 
       }
       
   }
   
   
   
   
}


inline
void
opt_feat::create_gmm_action(field<string>peo_train, int in_Ncent, int run)
{ 
  N_cent = in_Ncent;
  cout << "# clusters: " << N_cent << endl;

  
  for (uword act = 0 ; act < actions.n_rows;  ++act) {
    
    cout << "Calculating GMM for action " << actions(act) << endl;
    mat mat_features_tmp;
    mat mat_features;
      
    for (uword pe=0; pe<peo_train.n_rows; ++pe)    {
      mat mat_features_person_i;
      
      
       std::stringstream tmp_ss4;
       tmp_ss4 << "./features/train/feature_vectors_dim" << dim << "_" << peo_train (pe) << "_" << actions(act);
       //tmp_ss4 << "./features/train/feature_vectors_" << peo_train (pe) << "_" << actions(act);
       //cout << "Doing for " << tmp_ss4.str() << " ";
       mat_features_person_i.load( tmp_ss4.str() );
       if (mat_features_person_i.n_cols>0)
       {
	 mat_features_tmp	 = join_rows( mat_features_tmp, mat_features_person_i );
       }
       //cout << "vectors: " << mat_features_tmp.n_cols << " ";
       
    }
    
    
    
    //cout << endl;
    //cout << "Final rows & cols " << mat_features_tmp.n_rows << " & " << mat_features_tmp.n_cols << endl;
    
    const uword N_max = 50000;  // maximum number of vectors
      if (mat_features_tmp.n_cols > N_max)
      {
	 ivec tmp1 = randi( N_max, distr_param(0,mat_features_tmp.n_cols-1) );
	 ivec tmp2 = unique(tmp1);
	 uvec my_indices = conv_to<uvec>::from(tmp2);
	 mat_features = mat_features_tmp.cols(my_indices);  // extract a subset of the columns
       }
       else
       {
	 mat_features = mat_features_tmp;
	 
      }
      
       mat_features_tmp.reset();
    
    
      //cout << "r&c "<<  mat_features.n_rows << " & " << mat_features.n_cols << endl;
      gmm_diag gmm_model;
      gmm_diag bg_model;
      
      
      
      bool status_em = false;
      int rep_em=0;
      
      while (!status_em)
      {
	bool status_kmeans = false;
	//int rep_km = 0;
	
	while (!status_kmeans)
      {
	arma_rng::set_seed_random();

	status_kmeans = gmm_model.learn(mat_features, N_cent, eucl_dist, random_subset, 10, 0, 1e-5, false);   //Only Kmeans
	bg_model = gmm_model;
	//rep_km++;
      }

	
	status_em = gmm_model.learn(mat_features, N_cent, eucl_dist, keep_existing, 0, 10, 1e-5, false);   //Only EM
	rep_em++;
	
	if (rep_em==9)
	{
	  status_em = true;
	  gmm_model = bg_model;
	  
	}
	  
	}
	
	
	cout <<"EM was repeated " << rep_em << endl;

      
      
      
      
      std::stringstream tmp_ss5;
      tmp_ss5 << "./run"<< run <<"/gmm_models/Ng" << N_cent << "_" << actions(act)<< "_dim" <<dim; 
      cout << "Saving GMM in " << tmp_ss5.str() << endl;
      gmm_model.save( tmp_ss5.str() );
      cout << endl;
     
    }
  }




//******************TESTING MULTI ACTIONS***********************************
//***************************************************************************

///change this one :)

//load videos and labels list


inline 
void 
opt_feat::feature_multi_action( field<string> peo_test )
{
 
  ///AQUI VOY!!!!!!!!
  ///Ya funciona bn. Donde no vectores de caracteristicas el label es -1
  ///y creo que la matrix de vectores esta vacia. Probar cuando hagas Testing

  
  int n_peo_test =  peo_test.n_rows;
  
  for (int pe = 0; pe <n_peo_test; ++pe ){ //videos.n_rows


     std::stringstream ss_features;
     ss_features << "./features/dense/" << peo_test(pe) ;
     
     mat dense_features;
     dense_features.load( ss_features.str() );
     
     cout << ss_features.str() << endl;
     cout << "r&c: " << dense_features.n_rows << " & " << dense_features.n_cols << endl;
     int num_feat_vect = dense_features.n_rows;
     //getchar();
     
     //load labels and range
     std::stringstream ss_label_name;
     ss_label_name << path <<  peo_test (pe) << "_unique_verbs_labels.dat";
     std::string sLabel = ss_label_name.str();
     vec labels; 
     labels.load( sLabel );
     
     int nLabels =  labels.n_elem;
     
      
     field <mat> test_features_arma; 
     test_features_arma.set_size( nLabels );
     lab_feature_vectors.set_size( nLabels );
     lab_feature_vectors.fill(-1);
     
     std::vector <vec> feat_frame;
     
     cout << "# labels " << nLabels << endl;
     
     std::stringstream ss_range_frames;
     ss_range_frames << path <<  peo_test (pe) << "_start_end.dat";
     std::string sRange_frames = ss_range_frames.str();
     rowvec range_frame;
     range_frame.load( sRange_frames );
     range_frame.print("ini end");
     int ini_frame = range_frame(0);
     int end_frame = range_frame(1);
     int con_fr_te=0;
     
     for (int fv=1; fv<num_feat_vect; ++fv )
     {
       
      
       vec pre_one_vector= dense_features.row(fv-1).t();
       uword pre_fr_ind =  pre_one_vector(0); // 
       
       
       vec one_vector= dense_features.row(fv).t();
       uword fr_ind =  one_vector(0); // the first feature is the frame number
       
       if (fr_ind > ini_frame+1 &&  fr_ind <  nLabels )
       {
	 
 //cout << "fr_ind: " << fr_ind << " "<< endl;
	 
	 int lab_ind = fr_ind - ini_frame;
	 //cout << endl << "*******************************" << endl;
	 //cout << "lab_ind " << lab_ind << " ";
	 uword curr_pos = labels(lab_ind - 1) - 1; //lab_ind empeiza en UNO
	 uword prev_pos = labels(lab_ind -2) - 1;
	 
	 //cout << "curr_pos " << curr_pos << " ";
	 

	 
	 
	 //cout << "fr_ind & pre_fr_ind "<< fr_ind << " & "<< pre_fr_ind << " ";
	 //getchar();
	 
	 if (fr_ind == pre_fr_ind ) 
	 {
	   //cout <<"=="<< " ";
	   double is_zero = accu( abs( one_vector ) );
	   if (is_finite( one_vector ) && is_zero!=0 )
	   {
	     feat_frame.push_back(one_vector);
	     
	  }
	   //cout << "feat_frame.size() " << feat_frame.size() << " ";
	 }
	 
	 else 
	 {
	   //cout <<"!="<< " ";
	   mat feat_frame_i( dim,feat_frame.size() );
	   
	   for (uword l = 0; l<feat_frame.size(); ++l )
	   {  feat_frame_i.col(l) = feat_frame.at(l);	  }
	   
	   
	   feat_frame.clear();
	   double is_zero = accu( abs( one_vector ) );
	   if (is_finite( one_vector ) && is_zero!=0 )
	   {
	     feat_frame.push_back(one_vector);
	   }
	   
	   //cout << "feat_frame.size() " << feat_frame.size() << " ";
	   
	   
	   test_features_arma(lab_ind-1) = feat_frame_i;
	   lab_feature_vectors(lab_ind-1) = curr_pos;
	   //getchar();
	   //con_fr_te++;
	   
	  //solo agregar la que existe
	   
	  
	  //explica que haces
	   /*
	  if (fr_ind - 1 == pre_fr_ind)
	  {
	    cout << "fr_ind - 1 == pre_fr_ind " << " ";
	    test_features_arma(con_fr_te) = feat_frame_i;
	    lab_feature_vectors(con_fr_te) = prev_pos;
	    con_fr_te++;
	    //con_fr_te debe ser igual a prev_pos
	  }
	  
	  else
	  {
	    //explica que haces
	    cout << "fr_ind - 1 != pre_fr_ind " << " ";
	    for (int j=pre_fr_ind+1; j<= fr_ind-1; ++j)
	    {
	      cout << "j: " << j << " ";
	     test_features_arma(con_fr_te) = feat_frame_i;
	     lab_feature_vectors(con_fr_te) = prev_pos;
	     con_fr_te++;
	     
	      
	    }
	    
	    //getchar();
	    
	  }
	  */
	   
	}
	 
	 //cout << "fv: "<<fv << endl;
	 //cout << "lab_ind: " << lab_ind << endl;	 
	 //cout << "con_fr_te: " << con_fr_te << endl;
	 //lab_feature_vectors.save("Dios.dat", raw_ascii);
	 //getchar();
	
      }
       
    }
     

     
     ///end training

	


//To save:
	std::stringstream tmp_ss4;
	tmp_ss4 << "./features/multi_test/feat_dim" << dim << "_" << peo_test(pe);  
	
	std::stringstream tmp_vec_lab;
	tmp_vec_lab << "./features/multi_test/lab_"<< peo_test(pe);  
	
	
	//cout << tmp_ss4.str() << endl;
	//getchar();
	cout << "Saving " << endl;
	test_features_arma.save( tmp_ss4.str() );
	lab_feature_vectors.save( tmp_vec_lab.str(), raw_ascii );
	//cout << "Press a key" << endl;
	//getchar();
	
	
  }
  
}

inline 
void 
opt_feat::gmm_multi_action( field<string> peo_test, int in_Ncent, int L,  int run) 
{
  N_cent = in_Ncent;
  double ave_acc=0;
  
  field<mat> test_features_arma; // Features for frame i are in  arow of this field
  
  vec real_labels;
  
  cout << "Testing for GMM with " << N_cent << " centroids" << endl;
  
  
  vec likelihood_actions;
  vec likelihood_label;
  
  int n_peo_test =  peo_test.n_rows;
  
  for (int pi = 0; pi <n_peo_test; ++pi ){ 
    
    std::stringstream tmp_ss4;
    tmp_ss4 << "./features/multi_test/feat_dim" << dim << "_" << peo_test(pi);  
    test_features_arma.load( tmp_ss4.str() );
    
    
    ///load the labels after obtaining the multi_features
    //std::stringstream tmp_vec_lab;
    //tmp_vec_lab << "./features/multi_test/lab_"<< peo_test(pi); 
    //real_labels.load( tmp_vec_lab.str(), raw_ascii );
    
    ///load the original ones
     std::stringstream ss_label_name;
     ss_label_name << path <<  peo_test (pi) << "_unique_verbs_labels.dat";
     real_labels.load( ss_label_name.str(), raw_ascii );
     
    
    
    
    cout << tmp_ss4.str() << endl;
    cout << ss_label_name.str() << endl;
    
    
    int num_frames = test_features_arma.n_rows;
    
    cout << "num_frames: " << num_frames << endl;
    //getchar();
    
    mat log_prob;
    log_prob.zeros(num_frames, actions.n_rows); 
    
    cout << "Doing for person " << peo_test(pi) << endl;
    
   
    for ( int fr = 0; fr < num_frames -L +1 ; fr=fr+2)
    {
      //cout << fr << endl;
      mat mat_features;
      
      //cout << " j = " << fr << " to  j< " << fr+L << endl ;
      for (int j = fr; j< fr+L; j++)
      {
	//cout << j << " " ;
	
	if (test_features_arma(j).n_cols>0)
	{
	mat_features	 = join_rows( mat_features, test_features_arma(j) );
	}
// 	else
// 	{
// 	  cout << "j: "<< j << endl;
// 	  test_features_arma(j).print("test_features_arma");
// 	  cout << real_labels(j) << endl;
// 	  getchar();
// 	}
	
      }
      
      //cout << "r&c "<<  mat_features.n_rows << " & " << mat_features.n_cols << endl;

      
      
      //cout << endl;
      
      if (mat_features.n_cols>0)
      {
      mat likelihood_actions_lab = get_loglikelihoods(mat_features, run);
      likelihood_actions = likelihood_actions_lab.col(0);
      likelihood_label = likelihood_actions_lab.col(1);
      //likelihood_label.t().print("???");
      }
      ///dejalo asi a ver que pasa. Basicamente esta usando el anterior.
      ///no funciono, tonces likelihood_actions todo a zero a ver que :)
       else
       {
 	//cout << "fr: "<< fr << endl;
 	//cout << "Dios dime que puedo hacer aqui"<< endl;
 	//mat likelihood_actions_lab = get_loglikelihoods(mat_features, run);
 	likelihood_actions.zeros(actions.n_rows);
 	//likelihood_label.t().print("???");
       }
      
      //vec likelihood_actions = get_loglikelihoods(mat_features);
      
      
      //likelihood_actions_scenes.t().print();
      //cout << endl << "ini " << fr << " fin:" << fr + L-1 << endl;
      log_prob.rows(fr, fr + L-1).each_row() += likelihood_actions.t();
      
      
      //getchar();
      //cout << log_prob.rows(0, fr + L + 5) << endl;
      
      //mat X = log_prob.submat(0,0, fr + L + 5,6);
      //X.print();
      //X.submat( first_row, first_col, last_row, last_col )
      //getchar();
      
      
    }
    //log_prob.print();
    //cout << "Done here" << endl;
    //getchar();
    vec est_labels(num_frames);
    
    
    
    for ( int i = 0; i < num_frames; ++i)
    {
      //cout << " " << i;
      uword index;
      //double max_frame = 
      log_prob.row(i).max(index);
      //cout << "Log_prob_frame " << i << "= " << log_prob.row(i) << endl;
      
      //cout << "Max for " << log_prob.row(i) << " is " << max_frame << " pos: " << index<< endl;
      
      est_labels(i) = likelihood_label(index);
      //cout << "est_labels(i) " << est_labels(i) << endl;
      
      
      
      //getchar();
      
    }
    
    std::stringstream tmp_save_estlab;
    tmp_save_estlab<< "./run"<< run <<"/results/Ng_" << N_cent << "est_"<<peo_test(pi) <<"_dim" << dim << ".dat";  
    
    est_labels.save(tmp_save_estlab.str(), raw_ascii);
    
    
    std::stringstream tmp_save_real_lab;
    tmp_save_real_lab << "./run"<< run <<"/results/real_"<<peo_test(pi) <<".dat";  
    
    real_labels.save( tmp_save_real_lab.str(), raw_ascii );
    
    uvec comparing = find( est_labels == real_labels);
    double acc = comparing.n_elem;
    cout <<"performance for person "<<peo_test(pi)<<" is "<<setprecision(2)<<fixed<<100*acc/est_labels.n_elem << " %"<<endl;
    //Average performance not used as I'm running using 4 cores
    ave_acc = ave_acc + 100*acc/est_labels.n_elem;
    //getchar();
    
  }
  
  //cout << "Average performance is " << setprecision(2) << fixed << ave_acc/person.n_rows << " %"<<endl;
  
}


inline
mat
opt_feat::get_loglikelihoods(mat mat_features,  int run)
{

  //cout << "r&c "<<  mat_features.n_rows << " & " << mat_features.n_cols << endl;

  //cout << "get_loglikelihoods" << endl;
  mat likelihood_actions(actions.n_rows,2);
  vec likelihood_actions_lab(actions.n_rows); 
  vec likelihood_label(actions.n_rows);
  
  int pos = 0;
  
  
  for (uword act = 0; act < actions.n_rows; ++act)
  {
    gmm_diag gmm_model;
    std::stringstream tmp_ss5;
    tmp_ss5 << "./run"<< run <<"/gmm_models/Ng" << N_cent << "_" << actions(act)<< "_dim" <<dim; 
    //tmp_ss5 << "./run"<< run <<"/gmm_models/Ng" << N_cent << "_" << actions(act); 
    //cout << tmp_ss5.str() << endl;
    gmm_model.load( tmp_ss5.str());
    
    likelihood_actions_lab (pos) = gmm_model.avg_log_p(mat_features);
    likelihood_label (pos) = act;
    pos++;
  }
  
  
  likelihood_actions.col(0) = likelihood_actions_lab;
  likelihood_actions.col(1) = likelihood_label;
  
  //likelihood_actions.print();
  //cout << "Done. Press a key" << endl;
  //getchar();
  return likelihood_actions;
  
}

